﻿using Abide.Classes;
using Abide_AddOn_API;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

namespace Abide.Forms
{
    public partial class AddOnManager : Form
    {
        private List<ExtendedFactory> Factories
        {
            get;
            set;
        }

        public AddOnManager()
        {
            InitializeComponent();
        }
        private void AddOnManager_Load(object sender, EventArgs e)
        {
            LoadAddOns();
        }
        private void LoadAddOns()
        {
            //Setup
            Factories = new List<ExtendedFactory>();

            //Load...
            foreach (KeyValuePair<string, AddOnFactory> factory in AbideAddOnManager.Collections)
                Factories.Add(new ExtendedFactory(factory.Key, factory.Value));

            //...
            ListViewItem listItem = null;
            foreach (ExtendedFactory factory in Factories)
            {
                //Create
                listItem = new ListViewItem(factory.Name);
                listItem.SubItems.Add(string.Join(",", factory.FoundTypes));
                listItem.SubItems.Add(factory.AddOnDirectory);
                listItem.Tag = factory;

                //Add
                AddOnList.Items.Add(listItem);
            }
        }
        private void AddOnList_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Disable
            removeButton.Enabled = false;
            unloadButton.Enabled = false;

            //Get Factory ... ?
            ExtendedFactory factory = AddOnList.SelectedItems.Count > 0 ? AddOnList.SelectedItems[0].Tag as ExtendedFactory : null;

            //Update Property View
            if (factory != null)
            {
                addOnProperties.SelectedObject = AddOnList.SelectedItems.Count > 0 ? AddOnList.SelectedItems[0].Tag : null;
                removeButton.Enabled = true;
                unloadButton.Enabled = true;
            }
        }
        private void removeButton_Click(object sender, EventArgs e)
        {
            //Get Factory ... ?
            ExtendedFactory factory = AddOnList.SelectedItems.Count > 0 ? AddOnList.SelectedItems[0].Tag as ExtendedFactory : null;

            //Check
            if (factory != null)
            {
                if (FileLocked(Path.Combine(factory.AddOnDirectory, factory.PrimaryAssembly)))
                {
                    if (MessageBox.Show("Unable to delete AddOn because it is already loaded and locked by Abide." +
                        " Would you like to restart Abide in safe mode to remove AddOn?\r\n\r\nAlternatively"+
                        " You can unload the AddOn from the current session, this will not remove any files.", "Unable to delete",
                        MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == System.Windows.Forms.DialogResult.Yes)
                        Security.Restart("-s");
                }
                else
                {
                    //Delete
                    Directory.Delete(factory.AddOnDirectory, true);
                    AddOnList.Items.Remove(AddOnList.SelectedItems[0]);
                    removeButton.Enabled = false;
                    unloadButton.Enabled = false;
                }
            }
        }
        private void unloadButton_Click(object sender, EventArgs e)
        {
            //Get Factory ... ?
            ExtendedFactory factory = AddOnList.SelectedItems.Count > 0 ? AddOnList.SelectedItems[0].Tag as ExtendedFactory : null;

            //Check...
            if (factory != null)
            {
                //Remove
                Classes.AbideAddOnManager.Collections.Remove(factory.AddOnDirectory);
                AddOnList.Items.Remove(AddOnList.SelectedItems[0]);
                removeButton.Enabled = false;
                unloadButton.Enabled = false;
            }
        }
        private void RefreshButton_Click(object sender, EventArgs e)
        {
            AddOnList.Items.Clear();
            LoadAddOns();
        }
        private void closeButton_Click(object sender, EventArgs e)
        {
            Close();
        }

        private bool FileLocked(string fileLocation)
        {
            Stream fs = null;
            try { fs = new FileStream(fileLocation, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); }
            catch (IOException) { return true; }
            finally
            {
                if (fs != null)
                    fs.Close();
            }
            return false;
        }

        class ExtendedFactory : AddOnFactory
        {
            public string Name
            {
                get { return primaryAssembly.Name; }
            }
            public string PrimaryAssembly
            {
                get { return manifest.PrimaryAssembly; }
            }
            public string[] Files
            {
                get { return manifest.FileNames; }
            }
            public new string AddOnDirectory
            {
                get { return base.AddOnDirectory; }
                protected set { base.AddOnDirectory = value; }
            }
            public new string[] FoundTypes
            {
                get { return base.FoundTypes.ToArray(); }
                protected set { base.FoundTypes = new List<string>(value); }
            }
            public new string[] Tools
            {
                get
                {
                    List<string> value = new List<string>();
                    foreach (KeyValuePair<string, List<string>> type in base.Tools)
                        value.AddRange(type.Value);
                    return value.ToArray();
                }
            }
            public new string[] TabPages
            {
                get
                {
                    List<string> value = new List<string>();
                    foreach (KeyValuePair<string, List<string>> type in base.TabPages)
                        value.AddRange(type.Value);
                    return value.ToArray();
                }
            }
            public new string[] MenuButtons
            {
                get
                {
                    List<string> value = new List<string>();
                    foreach (KeyValuePair<string, List<string>> type in base.MenuButtons)
                        value.AddRange(type.Value);
                    return value.ToArray();
                }
            }
            public new string SettingsPage
            {
                get { return base.SettingsPage.Value; }
            }

            private AddOnManifest manifest;
            private AssemblyName primaryAssembly;

            public ExtendedFactory(string folder, AddOnFactory baseFactory):
                base()
            {
                //Clone into base
                base.AddOnDirectory = baseFactory.AddOnDirectory;
                base.FoundTypes = baseFactory.FoundTypes;
                base.Tools = baseFactory.Tools;
                base.TabPages = baseFactory.TabPages;
                base.MenuButtons = baseFactory.MenuButtons;
                base.SettingsPage = baseFactory.SettingsPage;

                //Load
                manifest = new AddOnManifest();
                manifest.Load(Path.Combine(folder, "Manifest.xml"));
                primaryAssembly = AssemblyName.GetAssemblyName(Path.Combine(folder, manifest.PrimaryAssembly));
            }
        }
    }
}
